package com.yami.shop.nft.common.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.EsOperationType;
import com.yami.shop.bean.event.ZteFileUploadEvent;
import com.yami.shop.bean.model.ShopDetail;
import com.yami.shop.common.bean.Minio;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.DataWebService;
import com.yami.shop.common.util.OssMultipartFile;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.nft.common.dao.NftApplyImgMapper;
import com.yami.shop.nft.common.dao.NftApplyMapper;
import com.yami.shop.nft.common.dao.NftDawMapper;
import com.yami.shop.nft.common.dao.NftDenomMapper;
import com.yami.shop.nft.common.model.NftApply;
import com.yami.shop.nft.common.model.NftApplyImg;
import com.yami.shop.nft.common.model.NftDaw;
import com.yami.shop.nft.common.model.NftDenom;
import com.yami.shop.nft.common.service.NftApplyService;
import com.yami.shop.service.AttachFileService;
import com.yami.shop.service.ShopDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Service
public class NftApplyServiceImpl extends ServiceImpl<NftApplyMapper, NftApply> implements NftApplyService {

    @Autowired
    private NftApplyMapper nftApplyMapper;

    @Autowired
    private NftApplyImgMapper nftApplyImgMapper;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private ShopConfig shopConfig;

    @Autowired
    private DataWebService dataWebService;

    @Autowired
    private NftDenomMapper nftDenomMapper;
    @Autowired
    private NftDawMapper nftDawMapper;
    @Autowired
    private ShopDetailService shopDetailService;
    @Autowired
    private AttachFileService attachFileService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "NftApplyList", key = "'nftApplyList'")
    public void saveNftApply(NftApply nftApply) {
        NftDenom nftDenom = new NftDenom();
        if (ObjectUtils.isEmpty(nftApply.getId())) {
            if (ObjectUtils.isEmpty(nftApply.getDenomId())) {
                throw new YamiShopBindException("区块链不能为空");
            }
            LambdaQueryWrapper<NftDenom> nftDenomLambdaQueryWrapper = new LambdaQueryWrapper<NftDenom>().eq(NftDenom::getDenomId, nftApply.getDenomId());
            nftDenom = nftDenomMapper.selectOne(nftDenomLambdaQueryWrapper);
        } else {
            NftApply addNftApply = nftApplyMapper.selectById(nftApply.getId());
            LambdaQueryWrapper<NftDenom> nftDenomLambdaQueryWrapper = new LambdaQueryWrapper<NftDenom>().eq(NftDenom::getDenomId, addNftApply.getDenomId());
            nftDenom = nftDenomMapper.selectOne(nftDenomLambdaQueryWrapper);
        }
        ShopDetail shopDetailByShopId = shopDetailService.getShopDetailByShopId(nftApply.getShopId());
        Map<String, String> stringObjectMap3 = new HashMap<>();
        String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/nftUser/getInfoForRomate";
        JSONObject jsonObject = dataWebService.hutoolPostWebService(url, stringObjectMap3, shopDetailByShopId.getApiUser(), shopDetailByShopId.getApiPassword());
        if (jsonObject.getInteger("code") == Constant.WARN) {
            throw new YamiShopBindException("该店铺暂无申请铸币权限");
        } else if (jsonObject.getInteger("code") == Constant.SUCCESS_CODE) {
            JSONObject datainfo = jsonObject.getJSONObject("data");
            if (Integer.valueOf(datainfo.getString("totalTimes")) < nftApply.getNftNum()) {
                throw new YamiShopBindException("该店铺铸币次数已用完");
            }
        }

        if (ObjectUtils.isEmpty(nftApply.getId())) {
            LambdaQueryWrapper<NftApply> ne = new LambdaQueryWrapper<NftApply>().eq(NftApply::getDenomId, nftApply.getDenomId()).ne(NftApply::getApplyStatus, 1);
            List<NftApply> list = list(ne);
            if (ObjectUtils.isNotEmpty(list)) {
                throw new YamiShopBindException("选择类别已存在申请中,请重新选择类别");
            }
            // 图片类型 水印材料处理
            if (nftApply.getNftApplyImg().getImgType() == 1 && nftApply.getNftApplyImg().getIsWatermark() == 1) {
                if (!nftApply.getNftApplyImg().getWatermarkUrl().contains(".zip")) {
                    throw new YamiShopBindException("请上传.zip格式压缩包");
                }
                try {
                    updateZipImg(nftApply.getDenomId(), nftApply.getNftApplyImg().getWatermarkUrl());
                } catch (YamiShopBindException e) {
                    throw new YamiShopBindException("压缩包内文件类型必须为.png");
                } catch (Exception e) {
                    throw new YamiShopBindException("上传文件异常");
                }
            }
            // 普通申请
            nftApply.setParentId(0);
            nftApply.setMintStatus(0);
            nftApply.setMintType(0);
            nftApply.setApplyStatus(0);
            nftApply.setRemarks(nftDenom.getBlockchainCode());
            nftApplyMapper.insert(nftApply);
            NftApplyImg nftApplyImg = nftApply.getNftApplyImg();
            nftApplyImg.setApplyId(nftApply.getId().intValue());
            nftApplyImgMapper.insert(nftApplyImg);
            if (nftApplyImg.getImgType() == 5) {
                // 中兴上传文件
                eventPublisher.publishEvent(new ZteFileUploadEvent(nftApplyImg.getImgName(), nftApplyImg.getImgUrl(), nftApplyImg.getId().longValue(), EsOperationType.SAVE));
            }
        } else {
            // 追加铸币
            NftApply addNftApply = nftApplyMapper.selectById(nftApply.getId());
            addNftApply.setParentId(nftApply.getId().intValue());
            addNftApply.setNftNum(nftApply.getNftNum());
            addNftApply.setMintType(1);
            addNftApply.setId(null);
            addNftApply.setMintStatus(0);
            addNftApply.setMintType(1);
            addNftApply.setApplyStatus(0);
            addNftApply.setRemarks(nftDenom.getBlockchainCode());
            nftApplyMapper.insert(addNftApply);
        }


    }

    // 处理zip文件 -- 水印材料
    private void updateZipImg(String denomId, String watermarkUrl) throws Exception {
        // 获取 zip 文件流
        Minio minio = shopConfig.getMinio();
        URL url = new URL(minio.getEndpoint() + "/" + minio.getBucketName() + "/" + watermarkUrl);
        URLConnection urlConnection = url.openConnection();
        urlConnection.connect();
        ZipInputStream zIn = new ZipInputStream(new BufferedInputStream(urlConnection.getInputStream()));
        Map<String, ByteArrayOutputStream> fileMaps = new HashMap<>();
        ZipEntry entry = null;
        File file = null;
        // 校验文件格式
        while ((entry = zIn.getNextEntry()) != null && !entry.isDirectory()) {
            if (!entry.getName().contains(".png")) {
                throw new YamiShopBindException("文件格式必须为.png");
            }
            // 保存文件
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int len = -1;
            while ((len = zIn.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
            out.close();
            fileMaps.put(entry.getName(), out);
        }
        // 保存文件信息
        for (Map.Entry<String, ByteArrayOutputStream> fileEntry : fileMaps.entrySet()) {
            MultipartFile ossMultipartFile = new OssMultipartFile(fileEntry.getKey(), ".png", fileEntry.getValue().toByteArray());
            attachFileService.uploadFileNoSave(ossMultipartFile.getBytes(), denomId + "/" + fileEntry.getKey());
        }
    }

    @Override
    @CacheEvict(cacheNames = "NftApplyList", key = "'nftApplyList'")
    public void updateNftApplyById(NftApply nftApply) {
        nftApplyMapper.updateById(nftApply);
    }

    @Override
    public NftApply getNftApplyInfo(Long nftApplyId) {
        return nftApplyMapper.getNftApplyInfo(nftApplyId, true);
    }

    @Override
    public NftApply getNftApplyAndImgInfo(Long nftApplyId) {
        return nftApplyMapper.getNftApplyAndImgInfo(nftApplyId);
    }

    @Override
    @Caching(evict = {@CacheEvict(cacheNames = "UserBalanceList", key = "'balanceList'")})
    public void removeCacheByNftApplyId() {

    }

    @Override
    @Cacheable(cacheNames = "UserBalanceList", key = "'balanceList'")
    public List<NftApply> getNftApplyList() {
        return nftApplyMapper.getNftApplyList();
    }

    @Override
    public IPage<NftApply> getNftApplyPage(PageParam<NftApply> page, NftApply nftApply) {
        return nftApplyMapper.getNftApplyPage(page, nftApply);
    }

    @Override
    public NftApply getNftApplyAndImgInfoByDenomId(String denomId) {
        return nftApplyMapper.getNftApplyAndImgInfoByDenomId(denomId);
    }

    @Override
    public NftApply getNftApplyAndImgInfoByDenomIdAndStatus(String denomId) {
        return nftApplyMapper.getNftApplyAndImgInfoByDenomIdAndStatus(denomId);
    }

    // 产权登记作品铸币
    public boolean copyrightApplyNft(NftApply nftApply, NftDenom nftDenom) {
        boolean resp = false;
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(nftApply.getShopId());
        Map<String, String> stringObjectMap3 = new HashMap<>();
        String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/nftUser/getInfoForRomate";
        JSONObject jsonObject = dataWebService.hutoolPostWebService(url, stringObjectMap3, shopDetail.getApiUser(), shopDetail.getApiPassword());
        if (jsonObject.getInteger("code") == Constant.WARN) {
            throw new YamiShopBindException("该店铺暂无申请铸币权限");
        } else if (jsonObject.getInteger("code") == Constant.SUCCESS_CODE) {
            JSONObject datainfo = jsonObject.getJSONObject("data");
            if (Integer.valueOf(datainfo.getString("totalTimes")) < nftApply.getNftNum()) {
                throw new YamiShopBindException("该店铺铸币次数已用完");
            }
        }
        List<NftApply> list = list(new LambdaQueryWrapper<NftApply>().eq(NftApply::getDenomId, nftDenom.getDenomId()).ne(NftApply::getApplyStatus, 1));
        if (!list.isEmpty()) {
            throw new YamiShopBindException("选择类别已存在申请中,请重新选择类别");
        }
        // 图片类型 水印材料处理
        if (nftApply.getNftApplyImg().getImgType() == 1 && nftApply.getNftApplyImg().getIsWatermark() == 1) {
            if (!nftApply.getNftApplyImg().getWatermarkUrl().contains(".zip")) {
                throw new YamiShopBindException("请上传.zip格式压缩包");
            }
            try {
                updateZipImg(nftDenom.getDenomId(), nftApply.getNftApplyImg().getWatermarkUrl());
            } catch (YamiShopBindException e) {
                throw new YamiShopBindException("压缩包内文件类型必须为.png");
            } catch (Exception e) {
                throw new YamiShopBindException("上传文件异常");
            }
        }
        // 普通申请
        nftApply.setParentId(0);
        nftApply.setMintStatus(1);
        nftApply.setMintType(0);
        nftApply.setApplyStatus(2);
        nftApply.setRemarks(nftDenom.getBlockchainCode());
        nftApply.setShopName(shopDetail.getShopName());
        if (nftApplyMapper.insert(nftApply) == 0) {
            return resp;
        }
        NftApplyImg nftApplyImg = nftApply.getNftApplyImg();
        nftApplyImg.setApplyId(nftApply.getId().intValue());
        if (nftApplyImgMapper.insert(nftApplyImg) == 0) {
            return resp;
        }

        for (int i = 0; i < nftApply.getNftNum(); i++) {
            String dawId = "daw" + IdUtil.simpleUUID();
            String operationId = "dtc" + IdUtil.simpleUUID();
            NftDaw nftDaw = new NftDaw();
            nftDaw.setNftApplyId(nftApply.getId());
            nftDaw.setDenomId(nftApply.getDenomId());
            if (nftDenom.getBlockchainCode().equals("avata")) {
                nftDaw.setOperationId(operationId);
            } else if (nftDenom.getBlockchainCode().equals("szavata")) {
                nftDaw.setOperationId(operationId);
                nftDaw.setNftCode(String.format("%05d", i + 1));
            } else if (nftDenom.getBlockchainCode().equals("hw")) {
                nftDaw.setDawId(String.valueOf(i + 1));
                nftDaw.setNftCode(String.format("%05d", i + 1));
            } else {
                nftDaw.setDawId(dawId);
                nftDaw.setNftCode(String.format("%05d", i + 1));
            }
            nftDaw.setBlockchainCode(nftDenom.getBlockchainCode());
            nftDaw.setUseStatus(0);
            nftDaw.setChainUpStatus(0);
            nftDaw.setCreateTime(new Date());
            resp = nftDawMapper.insert(nftDaw) > 0 ? true : false;

        }
        return resp;
    }

}
